/*
 * Copyright (c) 2021The red-star Project
 *
 * Licensed under the Apache License, version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.inyourcode.example.hotfix;

/**
 * @author JackLei
 */

import com.inyourcode.core.util.HttpMetehodCaller;
import com.inyourcode.core.compile.DynamicCompiler;
import com.inyourcode.core.spring.ClassHelper;
import com.inyourcode.core.transport.api.HttpAction;
import com.inyourcode.core.transport.netty.NettyHttpAcceptor;
import com.inyourcode.core.transport.netty.handler.acceptor.DefaultHttpRequestHandler;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class TestHotFixApp {

    public static void main(String[] args) throws InterruptedException {
        DefaultHttpRequestHandler defaultHttpRequest = new DefaultHttpRequestHandler();
        Method[] declaredMethods = HttActionTest.class.getDeclaredMethods();
        HttActionTest httActionObj = new HttActionTest();

        for (Method method : declaredMethods) {
            if (!method.isAnnotationPresent(HttpAction.class)) {
                continue;
            }
            HttpAction annotation = method.getAnnotation(HttpAction.class);
            HttpMetehodCaller httpMetehodCaller = new HttpMetehodCaller();
            httpMetehodCaller.setAction(annotation.action());
            httpMetehodCaller.setMethod(method);
            httpMetehodCaller.setObject(httActionObj);
            defaultHttpRequest.register(httpMetehodCaller);
        }

        NettyHttpAcceptor httpAcceptor = new NettyHttpAcceptor(8080, defaultHttpRequest);
        httpAcceptor.start();
        Thread.sleep(Integer.MAX_VALUE);
    }


    public static class HttActionTest {

        @HttpAction(action = "login")
        public Object login(Map<String, String> param) {
            String playerId = param.get("playerId");
            System.out.println(playerId);
            TestHotFixLogic.testLogic();
            TestHotFixLogic2.testLogic();
            return "playerid:" + playerId + ",login successed";
        }

        //127.0.0.1:8080/hotfix?jarName=hotfix-test.jar&clazzList=com.inyourcode.example.hotfix.TestHotFixLogic
        @HttpAction(action = "hotfix")
        public Object hotfix(Map<String, String> param) throws IOException {
            String jarName = param.get("jarName");
            jarName = "hotfix-path" + File.separator + jarName;

            String clazzList = param.get("clazzList");
            Set<String> filterClassSet = new HashSet<>();
            String[] split = clazzList.split(",");
            for (String clazzName : split) {
                filterClassSet.add(clazzName);
            }

            if (filterClassSet.isEmpty()) {
                return "hot fix error";
            }

            Map<String, byte[]> hotClassBytesMap = ClassHelper.readClassBytes(jarName, filterClassSet);
            if (hotClassBytesMap.size() != filterClassSet.size()) {
                return "hot fix error";
            }

            boolean redefineClass = ClassHelper.redefineClass(getClass().getClassLoader(), hotClassBytesMap);
            if (!redefineClass) {
                return "hot fix error";
            }

            TestHotFixLogic.testLogic();
            TestHotFixLogic2.testLogic();
            return "hot fix success";
        }

        //http://127.0.0.1:8080/putPatch?javaFileList=com.inyourcode.example.dynamiccompile.TestDynamicLogic,com.inyourcode.example.dynamiccompile.TestDynamicLogic2
        @HttpAction(action = "putPatch")
        public Object dynamicCompile(Map<String, String> params) {
            String javaFileList = params.get("javaFileList");
            String[] split = javaFileList.split(",");

            String rootPath = "dynamic-path" + File.separator;
            for (String javaFile : split) {
                try {
                    String fileName = javaFile.substring(javaFile.lastIndexOf(".") + 1);
                    Class dynamicClazz = DynamicCompiler.compileByJavaFile(javaFile, rootPath + fileName + ".java");
                    if (dynamicClazz == null) {
                        return "putPatch fail";
                    }
                    Runnable runnable = (Runnable) dynamicClazz.newInstance();
                    runnable.run();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                    return "putPatch fail";
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    return "putPatch fail";
                }
            }
            return "putPatch success";
        }
    }
}

